/*
 * Copyright (c) 2024 Black Sesame Technologies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gtest/gtest.h>

#include "dal/sequence_base.h"
#include "dal/string_sequence.h"

TEST(test_dal_sequence_init, dal_sequence)
{
    SEQUENCE(uint16_t) seq_int = {};
    INIT_SEQUENCE(uint16_t, &seq_int);

    ASSERT_EQ(seq_int._size, 0);
    ASSERT_EQ(seq_int._capacity, DAL_DEFAULT_CAPACITY);
    ASSERT_STREQ(seq_int._type_name, "uint16_t");
    ASSERT_EQ(seq_int._element_size, sizeof(uint16_t));
    ASSERT_NE(seq_int._handle, nullptr);

    DEEP_CLEAR_SEQUENCE(uint16_t, &seq_int);
}

TEST(test_dal_sequence_init_with_cap, dal_sequence)
{
    SEQUENCE(uint16_t) seq_int = {};
    INIT_SEQUENCE_WITH_CAPACITY(uint16_t, &seq_int, 100);

    ASSERT_EQ(seq_int._capacity, 100);
    DEEP_CLEAR_SEQUENCE(uint16_t, &seq_int);
}

TEST(test_dal_sequence_deep_delete, dal_sequence)
{
    SEQUENCE(uint16_t) seq_int;
    INIT_SEQUENCE(uint16_t, &seq_int);

    DEEP_CLEAR_SEQUENCE(uint16_t, &seq_int);

    EXPECT_EQ(seq_int._handle, nullptr);
}

TEST(test_dal_sequence_copy, dal_sequence)
{
    SEQUENCE(uint16_t) seq_int_src = {};
    INIT_SEQUENCE(uint16_t, &seq_int_src);
    int ret = -1;

    ret = PUSH_BACK_SEQUENCE(uint16_t, &seq_int_src, 10);
    ASSERT_EQ(ret, 0) << "PUSH_BACK_SEQUENCE falied";
    PUSH_BACK_SEQUENCE(uint16_t, &seq_int_src, 20);
    PUSH_BACK_SEQUENCE(uint16_t, &seq_int_src, 30);

    ASSERT_EQ(seq_int_src._size, 3);

    SEQUENCE(uint16_t) seq_int_des = {};

    INIT_SEQUENCE(uint16_t, &seq_int_des);

    ret = COPY_SEQUENCE(uint16_t, &seq_int_des, &seq_int_src);

    EXPECT_EQ(ret, 0) << "copy seq_inti  failed";

    ASSERT_EQ(seq_int_des._size, 3) << "seq_int_src size: " << seq_int_src._size;
    ASSERT_EQ(seq_int_des._capacity, DAL_DEFAULT_CAPACITY);
    EXPECT_STREQ(seq_int_des._type_name, "uint16_t");
    ASSERT_EQ(seq_int_des._element_size, sizeof(uint16_t));
    ASSERT_NE(seq_int_des._handle, nullptr);

    DEEP_CLEAR_SEQUENCE(uint16_t, &seq_int_src);
    DEEP_CLEAR_SEQUENCE(uint16_t, &seq_int_des);
}

TEST(test_dal_sequence_clear, dal_sequence)
{
    SEQUENCE(uint16_t) seq_int = {};
    INIT_SEQUENCE(uint16_t, &seq_int);
    PUSH_BACK_SEQUENCE(uint16_t, &seq_int, 10);
    PUSH_BACK_SEQUENCE(uint16_t, &seq_int, 20);
    PUSH_BACK_SEQUENCE(uint16_t, &seq_int, 30);

    CLEAR_SEQUENCE(uint16_t, &seq_int);

    ASSERT_EQ(seq_int._size, 0);
    DEEP_CLEAR_SEQUENCE(uint16_t, &seq_int);
}

TEST(test_dal_sequence_push_pop, dal_sequence)
{
    SEQUENCE(uint16_t) seq_int = {};
    INIT_SEQUENCE(uint16_t, &seq_int);
    EXPECT_EQ(SIZE_SEQUENCE(uint16_t, &seq_int), 0);

    PUSH_BACK_SEQUENCE(uint16_t, &seq_int, 10);
    PUSH_BACK_SEQUENCE(uint16_t, &seq_int, 20);
    PUSH_BACK_SEQUENCE(uint16_t, &seq_int, 30);
    ASSERT_EQ(SIZE_SEQUENCE(uint16_t, &seq_int), 3);

    POP_BACK_SEQUENCE(uint16_t, &seq_int);
    POP_BACK_SEQUENCE(uint16_t, &seq_int);
    POP_BACK_SEQUENCE(uint16_t, &seq_int);
    ASSERT_EQ(SIZE_SEQUENCE(uint16_t, &seq_int), 0);

    uint16_t es[5] = {1, 2, 3, 4, 5};
    int64_t original_pose = SIZE_SEQUENCE(uint16_t, &seq_int);
    PUSH_BACK_SEQUENCE_ARRAY(uint16_t, &seq_int, es, 5);
    ASSERT_EQ(SIZE_SEQUENCE(uint16_t, &seq_int), original_pose + 5);

    DEEP_CLEAR_SEQUENCE(uint16_t, &seq_int);
}

TEST(test_dal_sequence_get_set, dal_sequence)
{
    SEQUENCE(uint16_t) seq_int = {};
    INIT_SEQUENCE(uint16_t, &seq_int);
    int ret = -1;
    ret = PUSH_BACK_SEQUENCE(uint16_t, &seq_int, 10);
    ASSERT_EQ(ret, 0) << "first push failed";

    ret = PUSH_BACK_SEQUENCE(uint16_t, &seq_int, 20);
    ASSERT_EQ(ret, 0) << "second push failed";

    ret = PUSH_BACK_SEQUENCE(uint16_t, &seq_int, 30);
    ASSERT_EQ(ret, 0) << "third push failed";

    ASSERT_EQ(SIZE_SEQUENCE(uint16_t, &seq_int), 3);
    int result = 0;

    ret = GET_ELEMENT_SEQUENCE(uint16_t, &seq_int, 0, &result);
    ASSERT_EQ(ret, 0) << "first get failed, seq size: " << seq_int._size;
    ASSERT_EQ(result, 10);

    ret = GET_ELEMENT_SEQUENCE(uint16_t, &seq_int, 1, &result);
    ASSERT_EQ(ret, 0) << "second get failed, seq size: " << seq_int._size;
    ASSERT_EQ(result, 20);

    ret = GET_ELEMENT_SEQUENCE(uint16_t, &seq_int, 2, &result);
    ASSERT_EQ(ret, 0) << "third get failed, seq size: " << seq_int._size;
    ASSERT_EQ(result, 30);

    DEEP_CLEAR_SEQUENCE(uint16_t, &seq_int);
}

TEST(test_dal_string_seq_init, dal_string_seq)
{
    StringSeq_t str_seq = DEFAULT_STR_SEQ;
    ASSERT_EQ(string_seq_init(&str_seq, 10), 0);
    ASSERT_NE(str_seq.strs, (dal_string_t*)NULL);
    ASSERT_EQ(str_seq.capacity, 10);
    ASSERT_EQ(str_seq.length, 0);
}

TEST(test_dal_string_seq_expansion, dal_string_seq)
{
    StringSeq_t str_seq = DEFAULT_STR_SEQ;
    ASSERT_EQ(string_seq_init(&str_seq, 10), 0);
    ASSERT_EQ(string_seq_expansion(&str_seq, 20), 0);
    ASSERT_EQ(str_seq.capacity, 20);
}

TEST(test_dal_string_seq_reset, dal_string_seq)
{
    StringSeq_t str_seq = DEFAULT_STR_SEQ;
    ASSERT_EQ(string_seq_init(&str_seq, 10), 0);
    ASSERT_EQ(string_seq_reset(&str_seq), 0);

    ASSERT_EQ(str_seq.capacity, 0);
    ASSERT_EQ(str_seq.length, 0);
    ASSERT_EQ(str_seq.strs, (dal_string_t*)NULL);
}

TEST(test_dal_string_seq_push, dal_string_seq)
{
    StringSeq_t str_seq = DEFAULT_STR_SEQ;
    ASSERT_EQ(string_seq_init(&str_seq, 10), 0);
    dal_string_t str = DEFAULT_STRING;
    SET_STRING(&str, "test_string", 11);
    ASSERT_EQ(string_seq_push(&str_seq, &str), 0);
    ASSERT_EQ(str_seq.length, 1);

    RESET_STRING(&str);
    string_seq_reset(&str_seq);
}

TEST(test_dal_string_seq_size, dal_string_seq)
{
    StringSeq_t str_seq = DEFAULT_STR_SEQ;
    ASSERT_EQ(string_seq_init(&str_seq, 10), 0);
    dal_string_t str = DEFAULT_STRING;
    SET_STRING(&str, "test_string", 11);
    ASSERT_EQ(string_seq_push(&str_seq, &str), 0);
    ASSERT_EQ(str_seq.length, string_seq_size(&str_seq));

    RESET_STRING(&str);
    string_seq_reset(&str_seq);
}

TEST(test_dal_string_seq_clear, dal_string_seq)
{
    StringSeq_t str_seq = DEFAULT_STR_SEQ;
    ASSERT_EQ(string_seq_init(&str_seq, 10), 0);
    dal_string_t str = DEFAULT_STRING;
    SET_STRING(&str, "test_string", 11);

    ASSERT_EQ(string_seq_push(&str_seq, &str), 0);
    ASSERT_EQ(string_seq_size(&str_seq), 1);

    ASSERT_EQ(string_seq_clear(&str_seq), 0);
    ASSERT_EQ(string_seq_size(&str_seq), 0);

    RESET_STRING(&str);
    string_seq_reset(&str_seq);
}

TEST(test_dal_string_seq_pop, dal_string_seq)
{
    StringSeq_t str_seq = DEFAULT_STR_SEQ;
    ASSERT_EQ(string_seq_init(&str_seq, 10), 0);

    dal_string_t str = DEFAULT_STRING;
    SET_STRING(&str, "test_string", 11);

    ASSERT_EQ(string_seq_push(&str_seq, &str), 0);
    ASSERT_EQ(string_seq_push(&str_seq, &str), 0);
    ASSERT_EQ(string_seq_size(&str_seq), 2);

    ASSERT_EQ(string_seq_pop(&str_seq), 0);
    ASSERT_EQ(string_seq_size(&str_seq), 1);

    RESET_STRING(&str);
    string_seq_reset(&str_seq);
}

TEST(test_dal_string_seq_get, dal_string_seq)
{
    StringSeq_t str_seq = DEFAULT_STR_SEQ;
    ASSERT_EQ(string_seq_init(&str_seq, 10), 0);

    dal_string_t str = DEFAULT_STRING;
    SET_STRING(&str, "test_string", 11);

    ASSERT_EQ(string_seq_push(&str_seq, &str), 0);

    dal_string_t str_tmp = {NULL, 0};
    ASSERT_EQ(string_seq_get(&str_seq, &str_tmp, 0), 0);
    ASSERT_EQ(str_tmp.length, str.length);
    ASSERT_EQ(strcmp(str_tmp.str, str.str), 0)
        << "str_tmp: " << str_tmp.str << ", str: " << str.str;

    RESET_STRING(&str);
    string_seq_reset(&str_seq);
}

TEST(test_dal_string_seq_set, dal_string_seq)
{
    StringSeq_t str_seq = DEFAULT_STR_SEQ;
    ASSERT_EQ(string_seq_init(&str_seq, 10), 0);

    dal_string_t str1 = DEFAULT_STRING;
    SET_STRING(&str1, "test_string 1", 13);

    dal_string_t str2 = DEFAULT_STRING;
    SET_STRING(&str2, "test_string 2", 13);

    ASSERT_EQ(string_seq_push(&str_seq, &str1), 0);

    dal_string_t str_tmp = {NULL, 0};
    ASSERT_EQ(string_seq_set(&str_seq, &str2, 0), 0);

    ASSERT_EQ(string_seq_get(&str_seq, &str_tmp, 0), 0);
    ASSERT_EQ(strcmp(str_tmp.str, str2.str), 0);
    ASSERT_EQ(str_tmp.length, str2.length);

    RESET_STRING(&str1);
    RESET_STRING(&str2);

    string_seq_reset(&str_seq);
}
